package 哈希表系列;

import java.util.*;

public class ThreeSum {
//    public List<List<Integer>> threeSum(int[] nums) {
//        //解法1：哈希法
//        List<List<Integer>> ans = new ArrayList<>();    //存放结果
//
//        for(int i = 0; i < nums.length; i++){
//            if(nums[i] > 0){
//                // 排序之后如果第一个元素已经大于零，那么不可能凑成三元组
//                break;
//            }
//            if(i > 0 && nums[i] == nums[i-1]){  //三元组元素a去重
//                continue;
//            }
//
//            Set<Integer> hashset = new HashSet<>();
//            for(int j = i + 1; j < nums.length; j++){
//                if(j > i + 2
//                        && nums[j] == nums[j-1]
//                        && nums[j-1] == nums[j-2]){// 三元组元素b去重
//                    continue;
//                }
//                int c = 0 - (nums[i] + nums[j]);
//                if(hashset.contains(c)){
//                    ans.add(Arrays.asList(nums[i],nums[j],c));
//                    hashset.remove(c);// 三元组元素c去重
//                }else {
//                    hashset.add(nums[j]);
//                }
//            }
//
//        }
//        return ans;
//    }

    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();    //存放结果
        Arrays.sort(nums);

        for(int i = 0; i < nums.length; i++){
            //如果排序后第一个大于0，则不存在三元组等于0
            if(nums[i]>0){
                break;
            }

            //正确去重方法，三元组a去重
            if(i > 0 && nums[i] == nums[i-1]){
                continue;
            }
            // 错误去重方法，将会漏掉-1,-1,2 这种情况
            /*
            if (nums[i] == nums[i + 1]) {
                continue;   //如果采用这种方法，会让第一个-1给略过，这样的话就只剩-1，2，就会漏掉-1,-1,-2这种情况
            }
            */

            int left = i + 1;
            int right = nums.length - 1;
            while(left < right){
                // 去重复逻辑如果放在这里，0，0，0 的情况，可能直接导致 right<=left 了，从而漏掉了 0,0,0 这种三元组
                /*
                while (right > left && nums[right] == nums[right - 1]) right--;
                while (right > left && nums[left] == nums[left + 1]) left++;
                */
                if(nums[i] + nums[left] + nums[right] > 0){
                    right--;
                }else if(nums[i] + nums[left] + nums[right] < 0){
                    left++;
                }else {
                    result.add(Arrays.asList(nums[i],nums[left],nums[right]));
                    // 去重逻辑应该放在找到一个三元组之后
                    while (right > left && nums[right] == nums[right - 1]) right--;
                    while (right > left && nums[left] == nums[left + 1]) left++;

                    // 找到答案时，双指针同时收缩
                    right--;
                    left++;
                }
            }
        }
        return result;
    }

}
